package com.swt.gap.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.csv.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.swt.gap.common.*;
import com.swt.gap.common.constant.CommonConstant;
import com.swt.gap.common.constant.GraphDbConstant;
import com.swt.gap.common.exception.NoMatchedTemplateException;
import com.swt.gap.common.graph.*;
import com.swt.gap.common.layout.GridLayout;
import com.swt.gap.common.layout.force2.ForceLayoutCustomGenerator;
import com.swt.gap.config.ServerConfig;
import com.swt.gap.dao.*;
import com.swt.gap.model.dto.ElementValueDTO;
import com.swt.gap.model.entity.*;
import com.swt.gap.model.graphmodel.*;
import com.swt.gap.model.graphmodel.EventRelationNodeConfig;
import com.swt.gap.model.graphmodel.Property;
import com.swt.gap.model.vo.*;
import com.swt.gap.model.vo.ImportGraphDataVO;
import com.swt.gap.model.vo.graph.*;
import com.swt.gap.service.*;
import com.swt.gap.util.*;
import com.swt.gap.util.CsvReader;
import com.swt.gap.util.excel.ExcelData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.neo4j.graphdb.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.*;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class GraphDataServiceImpl implements GraphDataService {

    private static final Integer START_ROW_INDEX = 1;
    private static final Integer END_ROW_INDEX = 50;
    private static final Integer BIG_ROW_COUNT = 2000;

    private static CsvReadConfig csvReadConfig = new CsvReadConfig();

    static {
        csvReadConfig.setContainsHeader(true);
    }

    private final ModelService modelService;
    private final Model2Service model2Service;
    private final EmbeddedNeo4j embeddedNeo4j;
    private final TaskDao taskDao;
    private final GraphProcessor graphProcessor;
    private final TaskFileModelMapper taskFileModelMapper;
    private final OntologyNodeDao ontologyNodeDao;
    private final TaskFileMapper taskFileMapper;
    private final SysIconMapper sysIconMapper;
    private final OntologyNodePropertyDao ontologyNodePropertyDao;
    private final ServerConfig serverConfig;
    private final FileDao fileDao;
    private final TaskFileService taskFileService;
    private final TaskLabelsDao taskLabelsDao;
    private final TaskRelationshipTypeDao taskRelationshipTypeDao;
    private final BankCardBinDao bankCardBinDao;
    private final GraphDataTransferServiceImpl graphDataTransferService;
    private final Neo4jTools neo4jTools;

    public GraphDataServiceImpl(ModelService modelService,
                                Model2Service model2Service,
                                EmbeddedNeo4j embeddedNeo4j,
                                TaskDao taskDao,
                                GraphProcessor graphProcessor,
                                TaskFileModelMapper taskFileModelMapper,
                                OntologyNodeDao ontologyNodeDao,
                                TaskFileMapper taskFileMapper,
                                SysIconMapper sysIconMapper,
                                OntologyNodePropertyDao ontologyNodePropertyDao,
                                ServerConfig serverConfig,
                                FileDao fileDao,
                                TaskFileService taskFileService,
                                TaskLabelsDao taskLabelsDao,
                                TaskRelationshipTypeDao taskRelationshipTypeDao,
                                BankCardBinDao bankCardBinDao,
                                GraphDataTransferServiceImpl graphDataTransferService,
                                Neo4jTools neo4jTools) {
        this.modelService = modelService;
        this.model2Service = model2Service;
        this.embeddedNeo4j = embeddedNeo4j;
        this.taskDao = taskDao;
        this.graphProcessor = graphProcessor;
        this.taskFileModelMapper = taskFileModelMapper;
        this.ontologyNodeDao = ontologyNodeDao;
        this.taskFileMapper = taskFileMapper;
        this.sysIconMapper = sysIconMapper;
        this.ontologyNodePropertyDao = ontologyNodePropertyDao;
        this.serverConfig = serverConfig;
        this.fileDao = fileDao;
        this.taskFileService = taskFileService;
        this.taskLabelsDao = taskLabelsDao;
        this.taskRelationshipTypeDao = taskRelationshipTypeDao;
        this.bankCardBinDao = bankCardBinDao;
        this.graphDataTransferService = graphDataTransferService;
        this.neo4jTools = neo4jTools;
    }

    @Override
    public FormDataVO getFormFileData(String savedFileName) {
        String filePath = CommonConstant.UPLOAD_DIR + savedFileName;
        if (savedFileName.endsWith(FileTypeEnum.EXCEL03.getSuffix()) || savedFileName.endsWith(FileTypeEnum.EXCEL07.getSuffix())) {
            ExcelData excelData = com.swt.gap.util.excel.ExcelUtil.getReader().read(filePath, START_ROW_INDEX,
                    END_ROW_INDEX);
            return new FormDataVO(excelData.getHeader(), excelData.getRows());
        } else if (savedFileName.endsWith(FileTypeEnum.CSV.getSuffix())) {

            CsvReader iTextReader = new CsvReader(filePath);
            List<String> header = iTextReader.getHeader();
            List<List<String>> rows = iTextReader.getSamplesWithoutHead(START_ROW_INDEX, END_ROW_INDEX);
            iTextReader.stopParsing();

            return new FormDataVO(header, rows);
        }
        return new FormDataVO();
    }

    @Override
    public String getTextFileData(String savedFileName) throws Exception {
        String filePath = CommonConstant.UPLOAD_DIR + savedFileName;
        StringBuilder fileContent = new StringBuilder();
        File file = new File(filePath);
        if (savedFileName.endsWith(FileTypeEnum.TXT.getSuffix())) {
            //判断编码格式
//            BufferedReader t1 = new BufferedReader(new InputStreamReader((new FileInputStream(file)),
//                    StandardCharsets.UTF_8));
//            int len1 = t1.readLine().length();
//            BufferedReader t2 = new BufferedReader(new InputStreamReader((new FileInputStream(file)), "gbk"));
//            int len2 = t2.readLine().length();
//            InputStreamReader isr = null;
//            if (len1 <= len2) {
//                isr = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
//            } else {
//                isr = new InputStreamReader(new FileInputStream(file), "gbk");
//            }
//            BufferedReader br = new BufferedReader(isr)

//            String line;
//            while ((line = br.readLine()) != null) {
//                line += '\n';
//                fileContent.append(line);
//            }
//            try {
//                br.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }

            String filecharset = FileCharsetUtil.getFilecharset(file);
            BufferedReader br = null;
            try {
                InputStreamReader isr = new InputStreamReader(new FileInputStream(file), filecharset);

                br = new BufferedReader(isr);
                String line;
                while ((line = br.readLine()) != null) {
                    line +='\n';
                    fileContent.append(line);
                }
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

        } else if (savedFileName.endsWith(FileTypeEnum.WORD03.getSuffix())) {
            FileInputStream fis = new FileInputStream(file);
            WordExtractor wordExtractor = new WordExtractor(fis);
            String text = wordExtractor.getText();
            fileContent.append(text);
        } else if (savedFileName.endsWith(FileTypeEnum.WORD07.getSuffix())) {
            OPCPackage opcPackage = POIXMLDocument.openPackage(filePath);
            POIXMLTextExtractor extractor = new XWPFWordExtractor(opcPackage);
            String text = extractor.getText();
            fileContent.append(text);
        }

        return fileContent.toString();
    }

    @Override
    public ParseEntityVO parseEntity(ParseEntityParamsVO fileInfo) {
        ParseEntityVO retValue = new ParseEntityVO();
        List<String> header = Arrays.asList("军演事件,时间,地点,国家,部队,装备".split(","));
        List<String> row = Arrays.asList("锐剑-2019@2018-11-12@东京@美国,日本@美海军,美海军论战队,日本海上自卫队@里根号航母,出云号直升机航母,F-35".split("@"));
        List<List<String>> rows = new ArrayList<>();
        rows.add(row);
        retValue.setFormData(new FormDataVO(header, rows));

        List<GraphNeo4jVO.Node> nodes = new ArrayList<>();
        List<GraphNeo4jVO.Link> links = new ArrayList<>();

        GraphNeo4jVO.Node fileNode = new GraphNeo4jVO.Node();
        String savedFileName = fileInfo.getSavedFileName();
        String fileName = savedFileName.substring(savedFileName.lastIndexOf("_") + 1);
        fileNode.setName(fileName);
        fileNode.setId(UUID.randomUUID().toString());
        nodes.add(fileNode);

        GraphNeo4jVO.Node entityLabelNode = new GraphNeo4jVO.Node();
        entityLabelNode.setName("军演事件");
        entityLabelNode.setId(UUID.randomUUID().toString());
        nodes.add(entityLabelNode);

        GraphNeo4jVO.Link link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(fileNode.getId());
        link.setEndNodeId(entityLabelNode.getId());
        links.add(link);

        GraphNeo4jVO.Node entityNode = new GraphNeo4jVO.Node();
        entityNode.setName("锐剑-2019");
        entityNode.setId(UUID.randomUUID().toString());
        nodes.add(entityNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(entityLabelNode.getId());
        link.setEndNodeId(entityNode.getId());
        links.add(link);

        entityLabelNode = new GraphNeo4jVO.Node();
        entityLabelNode.setName("国家");
        entityLabelNode.setId(UUID.randomUUID().toString());
        nodes.add(entityLabelNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(fileNode.getId());
        link.setEndNodeId(entityLabelNode.getId());
        links.add(link);

        entityNode = new GraphNeo4jVO.Node();
        entityNode.setName("美国");
        entityNode.setId(UUID.randomUUID().toString());
        nodes.add(entityNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(entityLabelNode.getId());
        link.setEndNodeId(entityNode.getId());
        links.add(link);

        entityNode = new GraphNeo4jVO.Node();
        entityNode.setName("日本");
        entityNode.setId(UUID.randomUUID().toString());
        nodes.add(entityNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(entityLabelNode.getId());
        link.setEndNodeId(entityNode.getId());
        links.add(link);

        entityLabelNode = new GraphNeo4jVO.Node();
        entityLabelNode.setName("军队");
        entityLabelNode.setId(UUID.randomUUID().toString());
        nodes.add(entityLabelNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(fileNode.getId());
        link.setEndNodeId(entityLabelNode.getId());
        links.add(link);

        entityNode = new GraphNeo4jVO.Node();
        entityNode.setName("美海军");
        entityNode.setId(UUID.randomUUID().toString());
        nodes.add(entityNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(entityLabelNode.getId());
        link.setEndNodeId(entityNode.getId());
        links.add(link);

        entityNode = new GraphNeo4jVO.Node();
        entityNode.setName("美海军论战队");
        entityNode.setId(UUID.randomUUID().toString());
        nodes.add(entityNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(entityLabelNode.getId());
        link.setEndNodeId(entityNode.getId());
        links.add(link);

        entityNode = new GraphNeo4jVO.Node();
        entityNode.setName("日本海上自卫队");
        entityNode.setId(UUID.randomUUID().toString());
        nodes.add(entityNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(entityLabelNode.getId());
        link.setEndNodeId(entityNode.getId());
        links.add(link);

        entityLabelNode = new GraphNeo4jVO.Node();
        entityLabelNode.setName("装备");
        entityLabelNode.setId(UUID.randomUUID().toString());
        nodes.add(entityLabelNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(fileNode.getId());
        link.setEndNodeId(entityLabelNode.getId());
        links.add(link);

        entityNode = new GraphNeo4jVO.Node();
        entityNode.setName("里根号航母");
        entityNode.setId(UUID.randomUUID().toString());
        nodes.add(entityNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(entityLabelNode.getId());
        link.setEndNodeId(entityNode.getId());
        links.add(link);

        entityNode = new GraphNeo4jVO.Node();
        entityNode.setName("出云号直升机航母");
        entityNode.setId(UUID.randomUUID().toString());
        nodes.add(entityNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(entityLabelNode.getId());
        link.setEndNodeId(entityNode.getId());
        links.add(link);

        entityNode = new GraphNeo4jVO.Node();
        entityNode.setName("F-35");
        entityNode.setId(UUID.randomUUID().toString());
        nodes.add(entityNode);

        link = new GraphNeo4jVO.Link();
        link.setId(UUID.randomUUID().toString());
        link.setStartNodeId(entityLabelNode.getId());
        link.setEndNodeId(entityNode.getId());
        links.add(link);

        GraphNeo4jVO graph = new GraphNeo4jVO(nodes, links);
        retValue.setGraph(graph);
        return retValue;
    }

    @Override
    public TransferGraphDataVO generateGraphDataByFile(FormFileModelVO formFileModelVO) throws DateTimeParseException,
            NoMatchedTemplateException {
        StopWatch stopwatch = StopWatch.createStarted();
        List<GraphTemplate> listTemplate = formFileModelVO.getGraphModels();
        List<EventGraphModel> listEventTemplate = formFileModelVO.getEventModels();
        Integer taskId = formFileModelVO.getTaskId();
        List<FileFilterConfig> listFileFilterConfig = formFileModelVO.getFileFilterConfigList();

        Set<String> allMatchField = modelService.getMatchFieldsFromTemplate(listTemplate);

        Map<String, GraphNeo4jVO.Node> mapNodes = new HashMap<>();
        Map<String, GraphNeo4jVO.Link> mapLinks = new HashMap<>();
        cn.hutool.core.text.csv.CsvReader reader = CsvUtil.getReader(csvReadConfig);
        List<Map<String, String>> rowDataList = new ArrayList<>();
        for (FileFilterConfig fileFilterConfig : listFileFilterConfig) {
            String fileName = fileFilterConfig.getSavedFileName();
            List<FileFilterConfig.FieldFilterConfig> fieldFilterConfigList =
                    fileFilterConfig.getFieldFilterConfigList();
            String filePath = CommonConstant.UPLOAD_DIR + fileName;


            if (filePath.endsWith(FileTypeEnum.CSV.getSuffix())) {
                CsvData data = reader.read(FileUtil.file(filePath), StandardCharsets.UTF_8);
                List<String> header = data.getHeader();
                if (!allMatchField.isEmpty() && !header.containsAll(allMatchField)) {
                    throw new NoMatchedTemplateException("表头与模板不匹配");
                }
                List<CsvRow> csvRows = data.getRows();
                for (CsvRow csvRow : csvRows) {
                    Map<String, String> rowData = csvRow.getFieldMap();
                    rowDataList.add(rowData);
                }
            } else if (filePath.endsWith(FileTypeEnum.EXCEL03.getSuffix()) || filePath.endsWith(FileTypeEnum.EXCEL07.getSuffix())) {
                ExcelData data = com.swt.gap.util.excel.ExcelUtil.getReader().read(filePath);
                List<String> header = data.getHeader();
                if (!allMatchField.isEmpty() && !header.containsAll(allMatchField)) {
                    throw new NoMatchedTemplateException("表头与模板不匹配");
                }
                rowDataList = data.getFieldsMap();
            }
            System.out.println(" 转换 时间: " + stopwatch.getTime(TimeUnit.MILLISECONDS));
            processFileContent(taskId, fileName, listTemplate, listEventTemplate, mapNodes, mapLinks,
                    rowDataList, fieldFilterConfigList, 1);
            System.out.println(" 处理 时间: " + stopwatch.getTime(TimeUnit.MILLISECONDS));

        }

        List<GraphNeo4jVO.Node> listNodes = new ArrayList<>();
        mapNodes.forEach((k, v) -> listNodes.add(v));

        List<GraphNeo4jVO.Link> listLinks = new ArrayList<>();
        mapLinks.forEach((k, v) -> listLinks.add(v));


        TransferGraphDataVO retValue = new TransferGraphDataVO();
        retValue.setOriginalDataSize(rowDataList.size());
        retValue.setNodeSize(listNodes.size());
        retValue.setLinkSize(listLinks.size());
        retValue.setNodes(listNodes);
        retValue.setLinks(listLinks);
        return retValue;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean importGraphData(ImportGraphDataVO graphData) {
        boolean retValue = saveToEmbeddedNeo4j(graphData.getNodes(), graphData.getLinks(), graphData.getTaskId());
        TaskFileModel taskFileModel = new TaskFileModel();
        taskFileModel.setTaskId(graphData.getTaskId());
        taskFileModel.setFileId(graphData.getFileId());
        taskFileModel.setModelPicContent(graphData.getModelPicContent());
        if (null != graphData.getModelId()) {
            taskFileModel.setModelId(graphData.getModelId());
        }
        taskFileModelMapper.insertSelective(taskFileModel);

        taskFileMapper.updateStatus(graphData.getFileId(), graphData.getTaskId(), 1);
        return retValue;
    }

    @Override
    public TransferGraphDataVO generateGraphDataByText(TextFileModelVO textFileModelVO) throws DateTimeParseException{

        List<GraphTemplate> listTemplate = textFileModelVO.getGraphModels();
        List<EventGraphModel> listEventTemplate = textFileModelVO.getEventModels();
        Integer taskId = textFileModelVO.getTaskId();
        List<FileFilterConfig> listFileFilterConfig = textFileModelVO.getFileFilterConfigList();


        Map<String, GraphNeo4jVO.Node> mapNodes = new HashMap<>();
        Map<String, GraphNeo4jVO.Link> mapLinks = new HashMap<>();
        List<Map<String, String>> rowDataList = new ArrayList<>();
        for (FileFilterConfig fileFilterConfig : listFileFilterConfig) {
            String fileName = fileFilterConfig.getSavedFileName();
            List<FileFilterConfig.FieldFilterConfig> fieldFilterConfigList =
                    fileFilterConfig.getFieldFilterConfigList();

            List<String> header = textFileModelVO.getTextContent().getHeader();

            for (int i = 0; i < textFileModelVO.getTextContent().getRows().size(); i++) {
                Map<String, String> rowData = new HashMap<>();
                for (int j = 0; j < header.size(); j++) {
                    rowData.put(header.get(j), textFileModelVO.getTextContent().getRows().get(i).get(j));
                }
                rowDataList.add(rowData);
            }

            processFileContent(taskId, fileName, listTemplate, listEventTemplate, mapNodes, mapLinks,
                    rowDataList, fieldFilterConfigList, 2);

        }

        List<GraphNeo4jVO.Node> listNodes = new ArrayList<>();
        mapNodes.forEach((k, v) -> listNodes.add(v));

        List<GraphNeo4jVO.Link> listLinks = new ArrayList<>();
        mapLinks.forEach((k, v) -> listLinks.add(v));
        for(int i = 0; i < listNodes.size() && i < 200; i++) {
            GraphNeo4jVO.Node node = listNodes.get(i);
            String labels = String.join(",", node.getLabels());
            String icon = sysIconMapper.getIconFileByLabels(labels);
            icon = serverConfig.parseViewUrl(icon, 3);
            String name = (String) node.getProperties().get(GraphDbConstant.PROPERTY_NAME);
            if (Arrays.asList(labels.split(",")).contains("国家") || Arrays.asList(labels.split(",")).contains("装备")) {
                File file = new File(CommonConstant.ICON_PATH + name + ".png");
                if (file.exists()) {
                    icon = serverConfig.parseViewUrl(name + ".png", 3);
                }
            } else if (labels.contains("卡号") || labels.contains("账号")) {
                String bankIconFile = "";
                if (name.length() > 5) {
                    List<BankCardBin> bankCardBins = bankCardBinDao.selectByBin(name.substring(0, 6));
                    if (!bankCardBins.isEmpty()) {
                        bankIconFile = bankCardBins.get(0).getIconFile();
                    }
                }
                if (!StringUtils.isEmpty(bankIconFile)) {
                    icon = serverConfig.parseViewUrl(bankIconFile, 3);
                }
            }
            node.setIcon(icon);
        }
        TransferGraphDataVO retValue = new TransferGraphDataVO();
        retValue.setOriginalDataSize(rowDataList.size());
        retValue.setNodeSize(listNodes.size());
        retValue.setLinkSize(listLinks.size());
        retValue.setNodes(listNodes);
        retValue.setLinks(listLinks);
        return retValue;
    }

    @Override
    public TaskOverviewVO getTaskOverview(Integer taskId) {
        TaskOverviewVO retValue = new TaskOverviewVO();
        Task task = taskDao.selectByPrimaryKey(taskId);
        if (null != task) {
            List<TaskOverviewVO.NodeTypeCount> entityTypeCounts = new ArrayList<>();
            List<GraphNeo4jVO.Node> nodes = new ArrayList<>();
            List<GraphNeo4jVO.Link> links = new ArrayList<>();

            BeanUtils.copyProperties(task, retValue);
            GraphNeo4jVO.Node taskNode = new GraphNeo4jVO.Node();
            taskNode.setName(task.getTaskName());
            taskNode.setId(UUID.randomUUID().toString());
            taskNode.setIcon(serverConfig.parseViewUrl("hg-task-task.png", 3));
            nodes.add(taskNode);
//            List<OntologyEntity> ontologyEntities = ontologyEntityMapper.selectAll();

            List<TaskLabels> taskLabels = taskLabelsDao.listTaskLabelsByTaskId(taskId);


            for (NodeTypeEnum nodeTypeEnum : NodeTypeEnum.values()) {
                if (nodeTypeEnum != NodeTypeEnum.EXTERNAL) {
                    TaskOverviewVO.NodeTypeCount nodeTypeCount = new TaskOverviewVO.NodeTypeCount();
                    String label1 = nodeTypeEnum.getName();
                    nodeTypeCount.setNodeType(nodeTypeEnum.getCode());
                    nodeTypeCount.setNodeTypeName(label1);
                    List<TaskOverviewVO.NodeTypeCount> entityTypeCounts2 = new ArrayList<>();
                    final Long[] count1 = {0L};
                    taskLabels.forEach(taskLabels1 -> {
                        List<String> labels = Arrays.asList(taskLabels1.getLabels().split(","));
                        if (labels.contains(label1)) {
                            String label2 = labels.get(1);
                            String cypher = "MATCH (n:`" + label1 + "`:`" + label2 + "`{taskId:" + taskId
                                    + "}) RETURN count(n) as res";
                            long count2 = (long)neo4jTools.getOneResultByCypher(cypher).get(0);
                            if (count2 > 0) {
                                TaskOverviewVO.NodeTypeCount nodeTypeCount2 = new TaskOverviewVO.NodeTypeCount();
                                nodeTypeCount2.setNodeTypeName(label2);
                                nodeTypeCount2.setNodeCount(count2);
                                count1[0] += count2;
                                entityTypeCounts2.add(nodeTypeCount2);

                                GraphNeo4jVO.Node label2Node = new GraphNeo4jVO.Node();
                                label2Node.setName(label2);
                                label2Node.setId(UUID.randomUUID().toString());
                                Map<String, Object> props = new HashMap<>(2);
                                props.put("count", count2);
                                label2Node.setProperties(props);
                                String iconFile = sysIconMapper.getIconFileByLabels(label1 + "," + label2);
                                label2Node.setIcon(serverConfig.parseViewUrl(iconFile, 3));
                                nodes.add(label2Node);

                                GraphNeo4jVO.Link link = new GraphNeo4jVO.Link();
                                link.setId(UUID.randomUUID().toString());
                                link.setStartNodeId(taskNode.getId());
                                link.setEndNodeId(label2Node.getId());
                                links.add(link);
                            }
                        }
                    });

                    if (count1[0] > 0) {
                        nodeTypeCount.setNodeTypeCounts(entityTypeCounts2);
                        nodeTypeCount.setNodeCount(count1[0]);
                        entityTypeCounts.add(nodeTypeCount);
                    }
                }
            }
            retValue.setEntityTypeCounts(entityTypeCounts);
            retValue.setGraph(new GraphNeo4jVO(nodes, links));
        }

        return retValue;
    }

    @Override
    public List<GraphNeo4jVO.Node> getNodeByLabelAndTaskId(Integer taskId, Integer pageNum, Integer pageSize, String label) {

        String cypher = "MATCH (n:`" + label + "`) WHERE n.taskId=" + taskId + " RETURN n ORDER BY n.name ";
        if (null != pageNum && null != pageSize) {
            cypher = "MATCH (n:`" + label + "`) WHERE n.taskId=" + taskId + " RETURN n ORDER BY n.name SKIP " + ((pageNum - 1) * pageSize) + " LIMIT " + pageSize;
        }
        GraphNeo4jVO graph = graphProcessor.getNodeByCypher(cypher);
        return graph.getNodes();
    }

    @Override
    public List<String> getModelContentByTaskId(Integer taskId) {
        return taskFileModelMapper.selectModelContentByTaskId(taskId);
    }

    @Override
    public Boolean importDocGraph(DocImportVO record) {
        boolean retValue = false;
        GraphDatabaseService graphDatabaseService = embeddedNeo4j.getGraphDatabaseService();
        try (Transaction tx = graphDatabaseService.beginTx()) {
            Integer taskId = record.getTaskId();
            GraphNeo4jVO.Node docNode = record.getDocNode();
            Label[] labels = new Label[docNode.getLabels().size()];
            for (int i = 0; i < docNode.getLabels().size(); i++) {
                labels[i] = Label.label(docNode.getLabels().get(i));
            }
            Node docNodeDb = graphDatabaseService.createNode(labels);
            String id = String.valueOf((record.getSavedFileName()  + docNode.getName()).hashCode());
            docNodeDb.setProperty(GraphDbConstant.PROPERTY_KEY_ID, id);
            docNodeDb.setProperty(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);

            //来源
            JSONArray jaSource = new JSONArray();
            FileName sourceFileName = new FileName(record.getOriginalFileName(), record.getSavedFileName());
            JSONObject sourceFileNames = (JSONObject) JSON.toJSON(sourceFileName);
            jaSource.add(sourceFileNames);
            docNodeDb.setProperty(GraphDbConstant.PROPERTY_KEY_SOURCE, jaSource.toJSONString());

            Map<String, Object> props = docNode.getProperties();
            Optional.ofNullable(props).ifPresent(prop -> prop.forEach((k, v) -> {
                if (!StringUtils.isEmpty(k) && !StringUtils.isEmpty(v)) {
                    docNodeDb.setProperty(k, v.toString());
                }
            }));

            String savedFileName = record.getSavedFileName();
            String suffix= savedFileName.substring(savedFileName.lastIndexOf("."));
            FileTypeEnum fileTypeEnum = FileTypeEnum.getFileTypeEnumBySuffix(suffix);
            switch (fileTypeEnum) {
                case JPG:
                case JPEG:
                case PNG:
                case GIF:
                    docNodeDb.setProperty(GraphDbConstant.PROPERTY_KEY_ICON, "upload/" + savedFileName);
                    break;
                default:
                    break;

            }
            // 文件类型
            docNodeDb.setProperty(GraphDbConstant.PROPERTY_KEY_FILE_TYPE, fileTypeEnum.getDataTypeCode());

            addTaskLabels(taskId, docNode.getLabels());

            GraphNeo4jVO.Node otherNode = record.getOtherNode();
            Label[] labelsOtherNode = new Label[otherNode.getLabels().size()];
            StringBuilder sbLabels = new StringBuilder();
            List<String> otherLabels = otherNode.getLabels();
            for (int i = 0; i < otherLabels.size(); i++) {
                sbLabels.append(otherLabels.get(i));
                if(i < otherLabels.size() - 1) {
                    sbLabels.append(",");
                }
                labelsOtherNode[i] = Label.label(otherNode.getLabels().get(i));
            }
            String strLabels = sbLabels.toString();
            List<String> primaryKeys = ontologyNodePropertyDao.listPrimaryKeyByLabels(strLabels);
            Map<String, Object> mapParams = new HashMap<>();
            if (null != primaryKeys && primaryKeys.size() > 0) {
                primaryKeys.forEach(key -> {
//                    if ("名称".equals(key)) {
//                        key = "name";
//                    }
//                    if (null != otherNode.getProperties().get(key)) {
//                        mapParams.put("name", otherNode.getProperties().get(key));
//                    }
                    if (null != otherNode.getProperties().get(key)) {
                        mapParams.put(key, otherNode.getProperties().get(key));
                    }
                });
            }
            mapParams.put(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);
            Node otherNodeDb = null;
//            for (String otherLabel : otherLabels) {
                Label label = Label.label(otherLabels.get(1));
                ResourceIterator<Node> existNodes = graphDatabaseService.findNodes(label, mapParams);
                if (existNodes.hasNext()) {
                    otherNodeDb = existNodes.next();
//                    break;
                }
//            }
            if (null == otherNodeDb) {
                otherNodeDb = graphDatabaseService.createNode(labelsOtherNode);
                otherNodeDb.setProperty(GraphDbConstant.PROPERTY_KEY_ID, UUID.randomUUID().toString());
                otherNodeDb.setProperty(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);

                Map<String, Object> propsOther = otherNode.getProperties();
                for (Map.Entry<String, Object> entry : propsOther.entrySet()) {
                    otherNodeDb.setProperty(entry.getKey(), entry.getValue());
                }
                addTaskLabels(taskId, otherLabels);

            }

            RelationshipType type = RelationshipType.withName(record.getLink().getType());
            Relationship relationship = null;
            if (record.getLink().getDirection() == 2) {
                relationship = otherNodeDb.createRelationshipTo(docNodeDb, type);
            } else {
                relationship = docNodeDb.createRelationshipTo(otherNodeDb, type);
            }
            relationship.setProperty(GraphDbConstant.PROPERTY_KEY_ID, UUID.randomUUID().toString());
            relationship.setProperty(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);
            Map<String, Object> propsLink = record.getLink().getProperties();
            if (null != propsLink && !propsLink.isEmpty()) {
                for (Map.Entry<String, Object> entry : propsLink.entrySet()) {
                    relationship.setProperty(entry.getKey(), entry.getValue());
                }
            }
            addTaskRelationshipType(taskId, record.getLink().getType(), record.getLink().getOntologyRelationshipId());
            tx.success();
            retValue = true;
        }


        taskFileMapper.updateStatus(record.getFileId(), record.getTaskId(), 1);

        return retValue;
    }


    private void processFileContent(Integer taskId, String fileName, List<GraphTemplate> listTemplate,
                                    List<EventGraphModel> listEventTemplate,
                                    Map<String, GraphNeo4jVO.Node> mapNodes, Map<String, GraphNeo4jVO.Link> mapLinks,
                                    List<Map<String, String>> rows,
                                    List<FileFilterConfig.FieldFilterConfig> fieldFilterConfigList, Integer fileType) {


        GraphNeo4jVO.Node fileNode = new GraphNeo4jVO.Node();
        fileNode.setLabels(Arrays.asList("文档,文本文档".split(",")));
        String id = (String.valueOf(fileName.hashCode()));
        fileNode.setId(id);

        String icon = sysIconMapper.getIconFileByLabels("文档,文本文档");
        icon = serverConfig.parseViewUrl(icon, 3);
        fileNode.setIcon(icon);

        Map<String, Object> retProperties = new HashMap<>();
        //来源
        FileName sourceFileName = new FileName(fileName.substring(fileName.indexOf("_") + 1), fileName);
        Set<JSONObject> sourceFileNames = Collections.singleton((JSONObject) JSON.toJSON(sourceFileName));
        retProperties.put(GraphDbConstant.PROPERTY_KEY_SOURCE, sourceFileNames);
        retProperties.put(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);
        retProperties.put(GraphDbConstant.PROPERTY_KEY_ID, id);
        retProperties.put(GraphDbConstant.PROPERTY_NAME, fileName.substring(fileName.indexOf("_") + 1));
        fileNode.setProperties(retProperties);
        if (2 == fileType) {
            mapNodes.put(id, fileNode);
        }
        rows.forEach(row -> {
            // 后加的逻辑 需要优化
            boolean isMatched = true;
            for (FileFilterConfig.FieldFilterConfig fieldFilterConfig : fieldFilterConfigList) {
                isMatched = StringFilter.isMatchCondition(row.get(fieldFilterConfig.getFiled()),
                        fieldFilterConfig.getValue(), fieldFilterConfig.getConditionType());
                if (!isMatched) {
                    break;
                }
            }
            if (isMatched) {
                listTemplate.forEach(graphTemplate -> {
                    EntityTemplate entityTemplateOne = graphTemplate.getEntityTemplateOne();
                    EntityTemplate entityTemplateTwo = graphTemplate.getEntityTemplateTwo();
                    RelationshipTemplate relationshipTemplate = graphTemplate.getRelationshipTemplate();
                    GraphNeo4jVO.Node nodesOne = createNodesNoIcon(taskId, fileName, entityTemplateOne, row).get(0);
                    Optional.ofNullable(nodesOne).ifPresent(node -> mergeNode(mapNodes, node));
                    GraphNeo4jVO.Node nodeTwo = createNodesNoIcon(taskId, fileName, entityTemplateTwo, row).get(0);
                    Optional.ofNullable(nodeTwo).ifPresent(node -> mergeNode(mapNodes, node));
                    if (null != nodesOne && null != nodeTwo) {
                        String idOne = nodesOne.getId();
                        String idTwo = nodeTwo.getId();
                        GraphNeo4jVO.Link link = getLink(taskId, fileName, idOne, idTwo, nodesOne, nodeTwo,
                                relationshipTemplate, row);
                        if (null != link && null != relationshipTemplate.getRelationshipMergeProperty()) {
                            mergeLink(mapLinks, link, relationshipTemplate);
                        }
                    }
                });
                if (null != listEventTemplate) {
                    listEventTemplate.forEach(eventGraphModel -> {
                        GraphNeo4jVO.Node eventNode = createEventNode(taskId, fileName, eventGraphModel, row);
                        if (2 == fileType) {
                            String linkId = fileNode.getId() + eventNode.getId();
                            Map<String, Object> props = new HashMap<>();
                            props.put(GraphDbConstant.PROPERTY_KEY_ID, linkId);
                            props.put(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);

                            GraphNeo4jVO.Link docLink = GraphNeo4jVO.Link.builder()
                                    .id(linkId)
                                    .type("包含")
                                    .startNodeId(fileNode.getId())
                                    .endNodeId(eventNode.getId())
                                    .properties(props)
                                    .build();
                            mapLinks.put(docLink.getId(), docLink);
                        }
                        Optional.ofNullable(eventNode).ifPresent(node -> mergeNode(mapNodes, node));
//                        String type = "参与";
                        /*if (null != eventGraphModel.getRelationshipTemplate()) {
                            type = eventGraphModel.getRelationshipTemplate().getType();
                        }*/
                        List<GraphNeo4jVO.Node> relNodes = new ArrayList<>();
                        List<EventRelationNodeConfig> eventRelationNodes = eventGraphModel.getEventRelationNodes();
                        if (null != eventRelationNodes) {
                            eventRelationNodes.forEach(eventRelationNodeConfig -> {
                                List<GraphNeo4jVO.Node> relationNodes = createNodesNoIcon(taskId, fileName, eventRelationNodeConfig.getRelateNode(), row);
                                relNodes.addAll(relationNodes);
                                relationNodes.forEach(relationNode -> {
                                    Optional.ofNullable(relationNode).ifPresent(node -> mergeNode(mapNodes, node));
                                    GraphNeo4jVO.Link link = getLink(taskId, fileName, eventNode.getId(),
                                            relationNode.getId(), eventNode, relationNode,
                                            eventRelationNodeConfig.getRelationshipTemplate(), row);

                                    link.setMergeType("eventLink");
                                    mapLinks.put(link.getId(), link);
                                });
                            });
                        }

                        // 需要合并的事件相关节点，两两建边
                        List<OntologyNode> ontologyEntities = ontologyNodeDao.selectByLabels(eventGraphModel.getLabels());
                        if (null != ontologyEntities && !ontologyEntities.isEmpty() && ontologyEntities.get(0).getMerge()
                            && relNodes.size() == 2) {
                            GraphNeo4jVO.Node nodeOne = relNodes.get(0);
                            GraphNeo4jVO.Node nodeTwo = relNodes.get(1);
                            JSONArray jaTimes = new JSONArray();
                            jaTimes.add(eventNode.getProperties().get(GraphDbConstant.PROPERTY_AMOUNT));
                            Map<String, Object> properties = new HashMap<>();
                            properties.put("amount", eventNode.getProperties().get(GraphDbConstant.PROPERTY_AMOUNT));
                            properties.put("times", jaTimes.toJSONString());

                            String type = eventGraphModel.getLabels();
                            if (type.contains(",")) {
                                type = type.substring(type.indexOf(",") + 1);
                            }
                            GraphNeo4jVO.Link link = GraphNeo4jVO.Link.builder()
                                    .id(nodeOne.getId() + "_" + nodeTwo.getId())
                                    .type(type)
                                    .mergeType("eventLinkMerge")
                                    .startNodeId(nodeOne.getId())
                                    .endNodeId(nodeTwo.getId())
                                    .properties(properties)
                                    .build();

                            mapLinks.merge(link.getId(), link, (oldLink, newLink) -> {
                                oldLink.getProperties().merge("amount", newLink.getProperties().get("amount"),
                                        (oldAmount, newAmount) -> Double.parseDouble(String.format("%.2f",
                                                (double) oldAmount + (double) newAmount)));

                                oldLink.getProperties().merge("times", newLink.getProperties().get("times"),
                                        (oldTimes, newTimes) -> {
                                            JSONArray propValue = JSONArray.parseArray((String) oldTimes) ;
                                            propValue.addAll(JSONArray.parseArray((String) newTimes));
                                            return propValue.toJSONString();
                                        });
                                return oldLink;
                            });

                            String[] ids = link.getId().split("_");
                            if ((double) mapLinks.get(link.getId()).getProperties().get("amount") > 0) {
                                mapLinks.get(link.getId()).setStartNodeId(ids[1]);
                                mapLinks.get(link.getId()).setEndNodeId(ids[0]);
                            } else {
                                mapLinks.get(link.getId()).setStartNodeId(ids[0]);
                                mapLinks.get(link.getId()).setEndNodeId(ids[1]);
                            }

                        }
                    });
                }
            }

        });

    }


    private Boolean isMatchFilter(String type, String filterValue, String originValue) {
        boolean retValue = false;
        if (StringUtils.isEmpty(originValue)) {
            return false;
        }
        if (StringUtils.isEmpty(type)) {
            return true;
        }
        if (!StringUtils.isEmpty(type) && StringUtils.isEmpty(filterValue)) {
            return false;
        }
        switch (type) {
            case "等于":
                if (filterValue.equals(originValue)) {
                    retValue = true;
                }
                break;
            case "包含":
                if (originValue.contains(filterValue)) {
                    retValue = true;
                }
                break;
            case "开头以":
                if (originValue.startsWith(filterValue)) {
                    retValue = true;
                }
                break;
            case "大于":
                try {
                    if (Double.parseDouble(originValue) >= Double.parseDouble(filterValue)) {
                        retValue = true;
                    }
                } catch (Exception ignored) {
                }
                break;
            case "小于":
                try {
                    if (Double.parseDouble(originValue) <= Double.parseDouble(filterValue)) {
                        retValue = true;
                    }
                } catch (Exception ignored) {
                }
                break;
            default:
                break;
        }
        return retValue;
    }

    private Boolean saveToEmbeddedNeo4j(List<GraphNeo4jVO.Node> listNodes, List<GraphNeo4jVO.Link> listLinks,
                                        Integer taskId) {
        boolean retValue = false;
        GraphDatabaseService graphDatabaseService = embeddedNeo4j.getGraphDatabaseService();
        try (Transaction tx = graphDatabaseService.beginTx()) {
            Map<String, Node> mapNodes = new HashMap<>();
            listNodes.forEach(nodeData -> {
                Node existNode = null;
                ResourceIterator<Node> nodes = graphDatabaseService.findNodes(Label.label(nodeData.getLabels().get(1)),
                        GraphDbConstant.PROPERTY_KEY_ID, nodeData.getId());
                if (nodes.hasNext()) {
                    existNode = nodes.next();
                }
                if (null == existNode) {
                    Label[] labels = new Label[nodeData.getLabels().size()];
                    for (int i = 0; i < nodeData.getLabels().size(); i++) {
                        labels[i] = Label.label(nodeData.getLabels().get(i));
                    }
                    Node node = graphDatabaseService.createNode(labels);
                    String id  = nodeData.getId();
                    if (StringUtils.isEmpty(id)) {
                        id = String.valueOf((labels[1] + nodeData.getName() + taskId).hashCode());
                    }
                    node.setProperty(GraphDbConstant.PROPERTY_KEY_ID, id);
                    Map<String, Object> props = nodeData.getProperties();
                    Optional.ofNullable(props).ifPresent(prop -> prop.forEach((k, v) -> {
                        if (!StringUtils.isEmpty(k) && !StringUtils.isEmpty(v)) {
                            if(k.equals(GraphDbConstant.PROPERTY_KEY_SOURCE)) {
                                node.setProperty(k, JSON.toJSONString(v));
                            } else {
                                node.setProperty(k, v.toString());
                            }
                        }
                    }));
                    node.setProperty(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);

                    mapNodes.put(nodeData.getId(), node);

                    addTaskLabels(taskId, nodeData.getLabels());

                } else {
                    mapNodes.put(nodeData.getId(), existNode);
                }

            });
            for (GraphNeo4jVO.Link linkData : listLinks) {
                boolean isExistLink = false;

                RelationshipType type = RelationshipType.withName(linkData.getType());
                String startNodeId = linkData.getStartNodeId();
                Node startNode = mapNodes.get(startNodeId);
                String endNodeId = linkData.getEndNodeId();
                Node endNode = mapNodes.get(endNodeId);
                if (null != startNode && null != endNode) {
                    for (Relationship relationship : startNode.getRelationships(type)) {
                        if (relationship.getAllProperties().containsKey(GraphDbConstant.PROPERTY_KEY_ID) &&
                                relationship.getProperty(GraphDbConstant.PROPERTY_KEY_ID).equals(linkData.getId())) {
                            isExistLink = true;
                            break;
                        }
                    }
                    if (!isExistLink) {
                        org.neo4j.graphdb.Relationship relationship = startNode.createRelationshipTo(endNode, type);
                        String id = linkData.getId();
                        if (StringUtils.isEmpty(id)) {
                            id = String.valueOf((type + startNodeId + endNodeId + taskId).hashCode());
                        }

                        relationship.setProperty(GraphDbConstant.PROPERTY_KEY_ID, id);

                        Optional.ofNullable(linkData.getMergeType()).ifPresent(mergeType -> {
                            relationship.setProperty("mergeType", linkData.getMergeType());
                        });

                        Map<String, Object> props = linkData.getProperties();
                        Optional.ofNullable(props).ifPresent(prop -> prop.forEach((k, v) -> {
                            if (!StringUtils.isEmpty(k) && !StringUtils.isEmpty(v)) {
                                if (k.equals(GraphDbConstant.PROPERTY_KEY_SOURCE)) {
                                    relationship.setProperty(k, JSON.toJSONString(v));
                                } else {
                                    relationship.setProperty(k, v.toString());
                                }
                            }
                        }));
                        relationship.setProperty(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);
                        addTaskRelationshipType(taskId, linkData.getType(), linkData.getOntologyRelationshipId());
                    }
                }
            }
            tx.success();
            retValue = true;
        }
        return retValue;
    }

    /**
     * @author sx
     * @date 2019/9/26 17:39
     */
    private List<GraphNeo4jVO.Node> createNodesNoIcon(Integer taskId, String fileName, EntityTemplate entityTemplate,
                                                Map<String, String> row) {
        List<GraphNeo4jVO.Node> retValue = new ArrayList<>();
        String labels = entityTemplate.getLabels();
        String icon = "";
//        String icon = sysIconMapper.getIconFileByLabels(labels);
//        icon = serverConfig.parseViewUrl(icon, 3);
        Map<String, Object> retProperties = new HashMap<>();
        List<Property> properties = entityTemplate.getProperties();
        Optional.ofNullable(properties).ifPresent(props -> {
            props.forEach(property -> {
                String propFieldStandard = property.getFieldStandard();
                String propFieldOrigin = property.getFieldOrigin();
                if (!StringUtils.isEmpty(propFieldOrigin)) {
                    String filterType = property.getFilterType();
                    String filterValue = property.getFilterValue();
                    String originValue = "";
                    originValue = row.get(propFieldOrigin);

                    if (isMatchFilter(filterType, filterValue, originValue)) {
                        retProperties.put(propFieldStandard, originValue);
                    }
                }
            });
        });

        //来源
        FileName sourceFileName = new FileName(fileName.substring(fileName.indexOf("_") + 1), fileName);
        Set<JSONObject> sourceFileNames = Collections.singleton((JSONObject) JSON.toJSON(sourceFileName));
        retProperties.merge(GraphDbConstant.PROPERTY_KEY_SOURCE, sourceFileNames, (a, b) -> {
            Set<JSONObject> originValue = (Set<JSONObject>) a;
            originValue = new HashSet<>(originValue);
            originValue.addAll((Set<JSONObject>) b);
            return originValue;
        });
        //工作区属性
        retProperties.put(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);

        // 描述
        if (!StringUtils.isEmpty(entityTemplate.getDescriptionField())) {
            retProperties.put(GraphDbConstant.PROPERTY_DESCRIPTION, row.get(entityTemplate.getDescriptionField()));
        }

        retProperties.put(GraphDbConstant.PROPERTY_KEY_TYPE, entityTemplate.getType());

        String nameField = entityTemplate.getNameField();
        String nameValue = row.get(nameField).replaceAll("\"", "");
        boolean isEmptyPrimary = StringUtils.isEmpty(nameValue);
        if (isEmptyPrimary) {
            nameValue = "";
        }
        String[] names = nameValue.split(",");
        for (String name : names) {
            Map<String, Object> newProperties = new HashMap<>();
            retProperties.forEach(newProperties::put);
            newProperties.put(GraphDbConstant.PROPERTY_NAME, name);
            String id = String.valueOf((labels + name + taskId).hashCode());

            if (isEmptyPrimary) {

                id = String.valueOf((row.toString() + labels + entityTemplate.getId() + taskId).hashCode());
            }

            GraphNeo4jVO.Node retNode = new GraphNeo4jVO.Node();
            retNode.setLabels(Arrays.asList(labels.split(",")));
            retNode.setId(id);
            retNode.setIcon(icon);
            retNode.setProperties(newProperties);
            retValue.add(retNode);
        }

        return retValue;
    }

    private List<GraphNeo4jVO.Node> createNodes(Integer taskId, String fileName, EntityTemplate entityTemplate,
                                                Map<String, String> row) {
        List<GraphNeo4jVO.Node> retValue = new ArrayList<>();
        String labels = entityTemplate.getLabels();
        String icon = "";
//        String icon = sysIconMapper.getIconFileByLabels(labels);
//        icon = serverConfig.parseViewUrl(icon, 3);
        Map<String, Object> retProperties = new HashMap<>();
        List<Property> properties = entityTemplate.getProperties();
        Optional.ofNullable(properties).ifPresent(props -> {
            props.forEach(property -> {
                String propFieldStandard = property.getFieldStandard();
                String propFieldOrigin = property.getFieldOrigin();
                if (!StringUtils.isEmpty(propFieldOrigin)) {
                    String filterType = property.getFilterType();
                    String filterValue = property.getFilterValue();
                    String originValue = "";
                    originValue = row.get(propFieldOrigin);

                    if (isMatchFilter(filterType, filterValue, originValue)) {
                        retProperties.put(propFieldStandard, originValue);
                    }
                }
            });
        });

        //来源
        FileName sourceFileName = new FileName(fileName.substring(fileName.indexOf("_") + 1), fileName);
        Set<JSONObject> sourceFileNames = Collections.singleton((JSONObject) JSON.toJSON(sourceFileName));
        retProperties.merge(GraphDbConstant.PROPERTY_KEY_SOURCE, sourceFileNames, (a, b) -> {
            Set<JSONObject> originValue = (Set<JSONObject>) a;
            originValue = new HashSet<>(originValue);
            originValue.addAll((Set<JSONObject>) b);
            return originValue;
        });
        //工作区属性
        retProperties.put(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);

        // 描述
        if (!StringUtils.isEmpty(entityTemplate.getDescriptionField())) {
            retProperties.put(GraphDbConstant.PROPERTY_DESCRIPTION, row.get(entityTemplate.getDescriptionField()));
        }

        retProperties.put(GraphDbConstant.PROPERTY_KEY_TYPE, entityTemplate.getType());

        String nameField = entityTemplate.getNameField();
        String nameValue = row.get(nameField).replaceAll("\"", "");
        boolean isEmptyPrimary = StringUtils.isEmpty(nameValue);
        if (isEmptyPrimary) {
            nameValue = "";
        }
        String[] names = nameValue.split(",");
        for (String name : names) {
            Map<String, Object> newProperties = new HashMap<>();
            retProperties.forEach(newProperties::put);
            newProperties.put(GraphDbConstant.PROPERTY_NAME, name);
            String id = String.valueOf((labels + name + taskId).hashCode());

            if (isEmptyPrimary) {

                id = String.valueOf((row.toString() + labels + entityTemplate.getId() + taskId).hashCode());
            }
            /*if (Arrays.asList(labels.split(",")).contains("国家") || Arrays.asList(labels.split(",")).contains("装备")) {
                File file = new File(CommonConstant.ICON_PATH + name + ".png");
                if (file.exists()) {
                    icon = serverConfig.parseViewUrl(name + ".png", 3);
                }
            } else if (labels.contains("卡号") || labels.contains("账号")) {
                String bankIconFile = "";
                if (name.length() > 5) {
                    List<BankCardBin> bankCardBins = bankCardBinDao.selectByBin(name.substring(0, 6));
                    if (!bankCardBins.isEmpty()) {
                        bankIconFile = bankCardBins.get(0).getIconFile();
                    }
                }
                if (!StringUtils.isEmpty(bankIconFile)) {
                    icon = serverConfig.parseViewUrl(bankIconFile, 3);
                }
            }*/
            GraphNeo4jVO.Node retNode = new GraphNeo4jVO.Node();
            retNode.setLabels(Arrays.asList(labels.split(",")));
            retNode.setId(id);
            retNode.setIcon(icon);
            retNode.setProperties(newProperties);
//            retNode.setIsEmpty(isEmptyPrimary);
            retValue.add(retNode);
        }

        return retValue;
    }

    private GraphNeo4jVO.Link getLink(Integer taskId, String fileName, String startId, String endId,
                                      GraphNeo4jVO.Node source, GraphNeo4jVO.Node target,
                                      RelationshipTemplate relationshipTemplate, Map<String, String> row) {
        String relationType = relationshipTemplate.getType();
        //根据指定的field的值动态设置relationType
        String typeFiled = relationshipTemplate.getTypeFiled();
        if (!StringUtils.isEmpty(typeFiled)) {
            relationType = row.get(typeFiled);
        }
        DirectionConfig directionConfig = relationshipTemplate.getDirectionConfig();
        int type = directionConfig.getDirectionType();
        //默认左向右
        int directionType = 1;
        //直接指定了方向
        if (type == 1) {
            // 1左向右，2右向左
            directionType = directionConfig.getDirectionValue();
        }
        //根据设置字段的值判断方向
        else if (type == 2) {
            DirectionField directionField = directionConfig.getDirectionField();
            String field = directionField.getField();
            String leftToRightValue = directionField.getLeftToRightValue();
            String rightToLeftValue = directionField.getRightToLeftValue();
            String fieldValue = row.get(field);
            if (StringUtils.isEmpty(fieldValue)) {
                directionType = 1;
            } else {
                if (!StringUtils.isEmpty(leftToRightValue)) {
                    List<String> list1 = Arrays.asList(leftToRightValue.split(","));
                    if (list1.contains(fieldValue)) {
                        directionType = 1;
                    }
                }
                if (!StringUtils.isEmpty(rightToLeftValue)) {
                    List<String> list1 = Arrays.asList(rightToLeftValue.split(","));
                    if (list1.contains(fieldValue)) {
                        directionType = 2;
                    }
                }
            }
        }
        //
        if (directionType == 2) {
            String temp = startId;
            startId = endId;
            endId = temp;

            directionType = 1;
        }

        List<Property> properties = relationshipTemplate.getProperties();
        Map<String, Object> retProperties = new HashMap<>();
        Optional.ofNullable(properties).ifPresent(props -> {
            props.forEach(property -> {
                String propFieldStandard = property.getFieldStandard();
                String propFieldOrigin = property.getFieldOrigin();
                String filterType = property.getFilterType();
                String filterValue = property.getFilterValue();
                String originValue = row.get(propFieldOrigin);

                if (isMatchFilter(filterType, filterValue, originValue)) {
                    Set<String> propValues = Collections.singleton(originValue);
                    retProperties.merge(propFieldStandard, propValues, (a, b) -> {
                        List<String> propValue = new ArrayList<>((List<String>) a);
                        propValue.addAll((List<String>) b);
                        return propValue;
                    });
                }
            });
        });

        FileName sourceFileName = new FileName(fileName.substring(fileName.indexOf("_") + 1), fileName);
        Set<JSONObject> sourceFileNames = Collections.singleton((JSONObject) JSON.toJSON(sourceFileName));
        retProperties.merge(GraphDbConstant.PROPERTY_KEY_SOURCE, sourceFileNames, (a, b) -> {
            Set<JSONObject> originValue = (Set<JSONObject>) a;
            originValue = new HashSet<>(originValue);
            originValue.addAll((Set<JSONObject>) b);
            return originValue;
        });
        retProperties.put(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);

        String id = String.valueOf((row.toString() + relationType + relationshipTemplate.getId() + taskId).hashCode());

        // 显示属性
        String displayPropertyKey = relationshipTemplate.getDisplayPropertyKey();
        String displayPropertyValue = "";
        if (!StringUtils.isEmpty(displayPropertyKey)) {
            displayPropertyValue = row.get(displayPropertyKey);
            retProperties.put(displayPropertyKey, displayPropertyValue);
        }
        // 如果设置了合并方式，则显示属性合并
        RelationshipMergeProperty relationshipMergeProperty = relationshipTemplate.getRelationshipMergeProperty();
        if (null != relationshipMergeProperty) {
            Integer mergeType = relationshipMergeProperty.getMergeType();
            if (mergeType == 2) {
                id = String.valueOf((relationType + startId + endId + taskId).hashCode());
            } else if (mergeType == 3) {
                id = String.valueOf((relationType + startId + endId + directionType + taskId).hashCode());
            }

            //合并的属性值 追加或者求和
            Integer propertyMergeType = relationshipMergeProperty.getPropertyMergeType();
            if (!StringUtils.isEmpty(displayPropertyValue)) {
                if (propertyMergeType == 1) {
                    retProperties.put(displayPropertyKey, Collections.singletonList(displayPropertyValue));
                } else if (propertyMergeType == 2) {
                    try {
                        retProperties.put(displayPropertyKey, Double.valueOf(displayPropertyValue));
                    } catch (Exception e) {
                        log.error("非数字格式无法相加");
                    }
                }
//                retProperties.put(displayPropertyKey, Double.valueOf(displayPropertyValue));

            }
        }

        //时间属性
        TimeProperty timeProperty = relationshipTemplate.getTimeProperty();

        String timeField = timeProperty.getTimeField();
        String format = timeProperty.getFormat();
        String timePropertyValue = "";
        if (!StringUtils.isEmpty(timeField) && !StringUtils.isEmpty(format)) {
            timePropertyValue = row.get(timeField);
        }
        if (!StringUtils.isEmpty(timePropertyValue)) {
            retProperties.put(GraphDbConstant.PROPERTY_KEY_TIME, timePropertyValue);
        }
        if (!StringUtils.isEmpty(timeField)) {
            if (!StringUtils.isEmpty(timeField)) {
//                Date date = new SimpleDateFormat(format).parse(timePropertyValue);
//                timePropertyValue = new SimpleDateFormat(CommonConstant.DATETIME_FORMAT).format(date);
                if ("yyyy-MM-dd".equals(format) || "yyyy-M-d".equals(format) || "dd/MM/yyyy".equals(format)) {
                    LocalDate localDate = LocalDate.parse(timePropertyValue, DateTimeFormatter.ofPattern(format));
                    timePropertyValue =
                            DateTimeFormatter.ofPattern(CommonConstant.DATETIME_FORMAT).format(localDate.atStartOfDay());
                } else {
                    LocalDateTime localDateTime = LocalDateTime.parse(timePropertyValue,
                            DateTimeFormatter.ofPattern(format));
                    timePropertyValue =
                            DateTimeFormatter.ofPattern(CommonConstant.DATETIME_FORMAT).format(localDateTime);
                }
            }

            if (!StringUtils.isEmpty(timePropertyValue)) {
                retProperties.put(GraphDbConstant.PROPERTY_KEY_TIME, timePropertyValue);
            }
        }

        // 次数
        JSONArray times = new JSONArray();
        JSONObject oneTimes = new JSONObject();
        if (!StringUtils.isEmpty(displayPropertyKey)) {
            oneTimes.put(displayPropertyKey, displayPropertyValue);
            if (!StringUtils.isEmpty(timePropertyValue)) {
                oneTimes.put(GraphDbConstant.PROPERTY_KEY_TIME, timePropertyValue);
            }
            times.add(oneTimes);
        }
        retProperties.put(GraphDbConstant.PROPERTY_KEY_TIMES, times.toJSONString());
        return GraphNeo4jVO.Link.builder()
                .id(id)
                .type(relationType)
                .startNodeId(startId)
                .endNodeId(endId)
                .color(relationshipTemplate.getColor())
                .width(relationshipTemplate.getWidth())
                .displayPropertyKey(displayPropertyKey)
                .properties(retProperties)
                .ontologyRelationshipId(relationshipTemplate.getOntologyRelationshipId())
                .build();
    }

    /**
     * 合并重复结点，合并属性
     *
     * @author sx
     * @date 2019/9/26 20:06
     */
    private void mergeNode(Map<String, GraphNeo4jVO.Node> retNodes, GraphNeo4jVO.Node newNode) {
        String id = newNode.getId();
        retNodes.merge(id, newNode, (oldNodeValue, newNodeValue) -> {
            oldNodeValue.getProperties().forEach((k, v) -> {
                if (GraphDbConstant.PROPERTY_KEY_SOURCE.equals(k)) {
                    newNodeValue.getProperties().merge(k, v, (c, d) -> {
                        Set<JSONObject> originValue = new HashSet<>((Set<JSONObject>) c);
                        if (d.getClass() == String.class) {
                            JSONArray jaValue = JSON.parseArray((String) d);
                            for (Object o : jaValue) {
                                originValue.add((JSONObject) o);
                            }
                        } else {
                            originValue.addAll((Set<JSONObject>) d);
                        }
                        return originValue;
                    });
                }

            });
            return newNodeValue;
        });
    }

    private void mergeLink(Map<String, GraphNeo4jVO.Link> retLinks, GraphNeo4jVO.Link newLink,
                           RelationshipTemplate relationshipTemplate) {
        String displayPropertyKey = relationshipTemplate.getDisplayPropertyKey();
        Integer mergeType = relationshipTemplate.getRelationshipMergeProperty().getPropertyMergeType();
        String id = newLink.getId();
        TimeProperty timeProperty = relationshipTemplate.getTimeProperty();
        String timeField = timeProperty.getTimeField();
        String format = timeProperty.getFormat();

        retLinks.merge(id, newLink, (oldValueLink, newValueLink) -> {
            oldValueLink.getProperties().forEach((k, oldPropValue) -> {
                // 如果 设置了time属性，则不合并
                if (null != displayPropertyKey && displayPropertyKey.equals(k)) {
                    if (mergeType == 1) {
                        newValueLink.getProperties().merge(k, oldPropValue, (c, d) -> {
                            List<String> propValue = new ArrayList<>((List<String>) c);
                            if (d.getClass() == String.class) {
                                String[] arrValue = ((String) d).replace("[", "")
                                        .replace("]", "")
                                        .split(",");
                                Collections.addAll(propValue, arrValue);
                            } else {
                                propValue.addAll((List<String>) d);
                            }
                            return propValue;
                        });
                    } else if (mergeType == 2) {
                        try {
                            newValueLink.getProperties().merge(k, oldPropValue, (c, d) -> {
                                double dValue;
                                if (d.getClass() == String.class) {
                                    dValue = Double.parseDouble((String) d);
                                } else {
                                    dValue = (Double) d;
                                }
                                return Double.parseDouble(String.format("%.2f", dValue + (Double) c));
                            });
                        } catch (Exception e) {
                            log.error("非数字格式无法相加");
                        }
                    }
                } else if (GraphDbConstant.PROPERTY_KEY_SOURCE.equals(k)) {
                    newValueLink.getProperties().merge(k, oldPropValue, (c, d) -> {
                        Set<JSONObject> originValue = new HashSet<>((Set<JSONObject>) c);
                        if (d.getClass() == String.class) {
                            JSONArray jaValue = JSON.parseArray((String) d);
                            for (Object o : jaValue) {
                                originValue.add((JSONObject) o);
                            }
                        } else {
                            originValue.addAll((Set<JSONObject>) d);
                        }
                        return originValue;
                    });
                } else if (GraphDbConstant.PROPERTY_KEY_TIMES.equals(k)) {
                    // 次数
                    newValueLink.getProperties().merge(k, oldPropValue, (c, d) -> {
                        JSONArray propValue = JSONArray.parseArray((String) c) ;
                        if (d.getClass() == String.class) {
                            propValue.addAll(JSON.parseArray((String) d));
                        } else {
                            propValue.addAll((JSONArray) d);
                        }
                        return propValue.toJSONString();
                    });
                } else if (!GraphDbConstant.PROPERTY_KEY_ID.equals(k)
                        && !GraphDbConstant.PROPERTY_KEY_TASK_ID.equals(k)
                        && !GraphDbConstant.PROPERTY_KEY_TIME.equals(k)) {
                    newValueLink.getProperties().merge(k, oldPropValue, (c, d) -> {
                        Set<String> propValue = new HashSet<>();
                        if (c.getClass() == Double.class) {
                            propValue = new HashSet<>(Collections.singleton(String.valueOf(c)));
                        } else {
                            propValue = new HashSet<>(Collections.singleton((String) c));
                        }

                        if (d.getClass() == String.class) {
                            String[] arrValue = ((String) d).replace("[", "")
                                    .replace("]", "")
                                    .split(",");
                            Collections.addAll(propValue, arrValue);
                        } else if (d.getClass() == Double.class) {
                            propValue.addAll(new HashSet<>(Collections.singleton(String.valueOf(d))));
                        } else {
                            propValue.addAll((Set<String>) d);
                        }
                        return propValue;
                    });
                }
            });
            return newValueLink;
        });
    }


    private GraphNeo4jVO.Node createEventNode(Integer taskId, String fileName, EventGraphModel eventGraphModel,
                                              Map<String, String> row) {
        String labels = eventGraphModel.getLabels();
        String icon = sysIconMapper.getIconFileByLabels(labels);
        icon = serverConfig.parseViewUrl(icon, 3);

        Map<String, Object> retProperties = new HashMap<>();

        List<Property> properties = eventGraphModel.getProperties();
        Optional.ofNullable(properties).ifPresent(props -> {
            props.forEach(property -> {
                String propFieldStandard = property.getFieldStandard();
                String propFieldOrigin = property.getFieldOrigin();
                if (!StringUtils.isEmpty(propFieldOrigin)) {
                    String filterType = property.getFilterType();
                    String filterValue = property.getFilterValue();
                    String originValue = row.get(propFieldOrigin);

                    if (isMatchFilter(filterType, filterValue, originValue)) {
                        retProperties.put(propFieldStandard, originValue);
                    }
                }
            });
        });

        //来源
        FileName sourceFileName = new FileName(fileName.substring(fileName.indexOf("_") + 1), fileName);
        Set<JSONObject> sourceFileNames = Collections.singleton((JSONObject) JSON.toJSON(sourceFileName));
        retProperties.merge(GraphDbConstant.PROPERTY_KEY_SOURCE, sourceFileNames, (a, b) -> {
            Set<JSONObject> originValue = (Set<JSONObject>) a;
            originValue = new HashSet<>(originValue);
            originValue.addAll((Set<JSONObject>) b);
            return originValue;
        });
        //主键属性
//        retProperties.put(primaryKeyPropertyKey, primaryValue);



        String id = "";
        if (!StringUtils.isEmpty(eventGraphModel.getNameField())) {
            retProperties.put(GraphDbConstant.PROPERTY_NAME, row.get(eventGraphModel.getNameField()));
        }
        if (!StringUtils.isEmpty(eventGraphModel.getEventStartTime())) {
            retProperties.put("startTime",
                    TimeFormatUtil.transformToStandardFormat(row.get(eventGraphModel.getEventStartTime())));
        }
        if (!StringUtils.isEmpty(eventGraphModel.getEventEndTime())) {
            retProperties.put("endTime",
                    TimeFormatUtil.transformToStandardFormat(row.get(eventGraphModel.getEventEndTime())));
        }
        if (!StringUtils.isEmpty(eventGraphModel.getLocation())) {
            retProperties.put("location", row.get(eventGraphModel.getLocation()));
        }
        if (!StringUtils.isEmpty(eventGraphModel.getDescriptionField())) {
            retProperties.put(GraphDbConstant.PROPERTY_DESCRIPTION, row.get(eventGraphModel.getDescriptionField()));
        }

//        if (!StringUtils.isEmpty(eventGraphModel.getNameField())) {
//            retProperties.put(GraphDbConstant.PROPERTY_NAME, row.get(eventGraphModel.getNameField()));
//            id = String.valueOf((row.get(eventGraphModel.getNameField()) + labels + taskId).hashCode());
//        } else {
            id = String.valueOf((row.toString() + labels + taskId).hashCode());
//        }

        String amount = "0";
        if (!StringUtils.isEmpty(eventGraphModel.getAmountField())) {
            amount = row.get(eventGraphModel.getAmountField());
        } else {
            for (Property prop : eventGraphModel.getProperties()) {
                if ("交易金额".equals(prop.getFieldStandard())) {
                    amount = row.get(prop.getFieldStandard());
                    break;
                }
            }
        }
        if (labels.contains("交易")) {
            retProperties.put(GraphDbConstant.PROPERTY_MERGE_TYPE, "eventNode");
        }
        try {
            retProperties.put(GraphDbConstant.PROPERTY_AMOUNT, Double.parseDouble(amount));
        } catch(Exception e) {
            retProperties.put(GraphDbConstant.PROPERTY_AMOUNT, 0D);
        }
        retProperties.put(GraphDbConstant.PROPERTY_KEY_TASK_ID, taskId);

//        // 临时生成假数据
//        Double lng = 124d + Math.random() * 2;
//        Double lat = 20d + Math.random() * 10;
//        retProperties.put(GraphDbConstant.PROPERTY_KEY_LNG, lng.toString());
//        retProperties.put(GraphDbConstant.PROPERTY_KEY_LAT, lat.toString());

        GraphNeo4jVO.Node retNode = new GraphNeo4jVO.Node();
        retNode.setLabels(Arrays.asList(labels.split(",")));
        retNode.setId(id);
        retNode.setIcon(icon);
//        retNode.setDisplayPropertyKey(GraphDbConstant.PROPERTY_NAME);
        retNode.setProperties(retProperties);
//        retNode.setIsEmpty(false);
//        retNode.setAmount(Double.parseDouble(amount));
        return retNode;
    }

    public GraphNeo4jVO layout(GraphNeo4jVO graphNeo4jVO) {
        List<GraphNeo4jVO.Node> listNodes = graphNeo4jVO.getNodes();
        List<GraphNeo4jVO.Link> listLinks = graphNeo4jVO.getLinks();
        if (listNodes.size() > 500) {
            GridLayout layout = new GridLayout();
            layout.gridLayout(listNodes, 70, 30);
        } else {
            ForceLayoutCustomGenerator forceLayoutCustomGenerator = new ForceLayoutCustomGenerator();
            forceLayoutCustomGenerator.getLayout(listNodes, listLinks, 200);
        }
        return new GraphNeo4jVO(listNodes, listLinks);
    }


    private Integer addTaskLabels(Integer taskId, List<String> labels) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < labels.size(); i++) {
            sb.append(labels.get(i));
            if (i < labels.size() - 1) {
                sb.append(",");
            }
        }
        return taskLabelsDao.insertNotExists(new TaskLabels(taskId, sb.toString()));
    }

    private Integer addTaskRelationshipType(Integer taskId, String relationshipType, Integer ontologyRelationshipId) {

        return taskRelationshipTypeDao.insertNotExists(new TaskRelationshipType(taskId, relationshipType, ontologyRelationshipId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer importKB(Integer taskId, String fileName) throws IOException {
        String content = "【美菲“肩并肩”联合演习】美菲“肩并肩”联合演习（Balikatan Exercise），是美" +
                "国海军、海军陆战队和菲律宾海军的例行性年度演习，2019 年为该演习第 35 次举行。美海" +
                "军黄蜂号两栖戒备大队、陆战队第 31 远征部队等近 3500 人、菲律宾海军、陆战队近 4000" +
                "人参加，此外澳大利亚军方还派出了一个 50 人规模的代表团包括特种兵、医疗、工程和牧" +
                "师人员参加到了演习的部分科目中。演习从 4 月 1 日开始，4 月 12 日结束，涵盖两栖作" +
                "战、实弹演练、城市作战和反恐作战等 28 个演习科目，演习区域主要集中在菲律宾吕宋" +
                "岛、巴拉望岛、棉兰老岛及周边海空域。驻日美海军陆战队 121 战斗机攻击中队（VMFA-" +
                "121）10 架 F-35B 战斗机 首次随黄蜂号两栖攻击舰（USS Wasp，LHD-1）参加演习，主要参" +
                "加航空作战、对地攻击等科目。\n\n" +
                "【美菲“盾牌”联合演习】美菲“盾牌”联合演习（Exercise Salaknib 2019）是美菲" +
                "陆军之间开展的一个例行性年度演习，由美军太平洋陆军司令部与菲律宾陆军共同举办。" +
                "2019 年 3 月 4 日至 24 日在菲律宾帕拉延市麦格塞塞堡基地和新埃西哈省部分地区举行，美" +
                "陆军第 7 步兵师、菲律宾陆军第 7 步兵师共计 1600 余人参加，演习科目包括丛林战场训" +
                "练、双边指挥所演习、多主题专家交流以及合作健康交流、人道主义民事行动等。\n\n" +
                "【“海上勇士合作 3”联合演习】美菲“海上勇士合作 3”联合演习（KAMANDAG 3），" +
                "是由菲律宾主导美菲海军、陆战队共同参加的双边年度演习，同时日本自卫队也参加该演习" +
                "的部分演习科目。演习从 10 月 9 日开始持续至 10 月 18 日，演习区域涵盖菲律宾吕宋岛、" +
                "巴拉望岛等地，主要开展两栖作战、实弹射击、城市作战、航空作战和反恐行动、人道主义" +
                "救援和减灾演练。美菲日三国 首次联合开展两栖突击车训练，美菲之间 首次开展低空防御训" +
                "练和威胁反应训练。其中 10 月 12 日美日菲三国举行了两栖登陆作战演习，演习中美菲两国" +
                "士兵进行岸滩侦察，随后三国的两栖突击车（AAV）从菲律宾达沃号两栖运输舰（BRP Davao" +
                "Del Sur ，LD-602）、美海军杰曼敦号两栖船坞登陆舰（USS Germantown，LSD-42）实施抢" +
                "滩登陆，美菲两国实施安全警戒，日自卫队还主导了医疗撤运和减灾演练。\n\n" +
                "【“萨马萨马”海上训练活动】美菲“萨马萨马”海上训练活动（Maritime Training" +
                "Activity Sama Sama）是美菲年度海上联合训练演习，2019 年日海上自卫队 首次参加该演" +
                "习。这是该演习第 3 次举行，时间从 10 月 14 日持续至 21 日，演习地点主要集中在菲律宾" +
                "普林塞萨港及周边海域。美军参演兵力包括美海军濒海战斗舰蒙哥马利号（USS" +
                "Montgomery，LCS-8）、两栖船坞登陆舰杰曼敦号、远征快速运输船米利诺克特号（USNS" +
                "Millinocket ，T-EPF3）、打捞船打捞者号（USNS Salvor，ARS-52）、海警船斯特拉顿号" +
                "（USCG Stratton，VMSL-752）、1 架 P-8A 反潜巡逻机。演习分为岸基和海上演习两个阶" +
                "段。岸基阶段主要进行主题专家交流会，议题涵盖海域态势感知、部队防护、医疗、人道主" +
                "义援助和减灾、爆炸物处置、潜水和打捞行动、工程、航空和登临搜捕行动等。海上阶段包" +
                "括登临、搜捕演练、分离战术、搜救演练、直升机甲板着陆资格、防空和水面作战追踪等。\n\n" +
                "【“哈努曼守卫者 19”年度联合演习】美泰“哈努曼守卫者 19”年度联合演习" +
                "（Exercise Hanuman Guardian）是美太平洋陆军司令部与泰国陆军组织的例行性年度演" +
                "习。今年演习在泰国举行，时间从 1 月 28 日至 2 月 7 日。美国陆军第 2 步兵师斯特瑞克旅" +
                "战斗队共 800 人与泰国陆军第 2 步兵师机关机及第 12 步兵团 900 人参加，演习主要包括空" +
                "中演练、简易爆炸物应对处置技巧和主题专家讨论等。在今年演习中美陆军第 20 步兵团 5" +
                "营与泰国陆军第 12 步兵团举行了班战术演练；在联合参谋主题交流会环节，双方对两国陆" +
                "军军事决策过程进行了交流讨论；在简易爆炸物应对处置演练中，美陆军 303 军械营向泰国" +
                "陆军分享了他们从伊拉克和阿富汗战场上积累的简易爆炸装置处置技巧、程序以及相关经验" +
                "教训。\n\n" +
                "【“金色眼镜蛇”联合演习】“金色眼镜蛇”联合演习（Exercise Cobra Gold ）目前" +
                "是东南亚地区最大的多边联合年度演习，主要由美泰两国共同组织，日本、印尼、马来西" +
                "亚、新加坡等国参与，部分国家作为观察员国参加。2019 年是该演习第 38 次举行，时间从" +
                "2 月 12 日持续至 23 日，地点主要集中在泰国梭桃邑基地及周边海空域。美海军格林湾号两" +
                "栖船坞运输舰（USS Green Bay，LPD-20）、陆战队第 31 远征部队、空军第 35 战斗机中队" +
                "等 4500 余人参加。演习主要包括战场训练演习（FTX）、社区人道主义民事援助（HCA）和" +
                "人道主义救援与减灾演习三部分。美空军第 35 战斗机中队 6 架 F-16C 战斗机从韩国群山基" +
                "地转场至泰国呵叻空军基地参加“金色眼镜蛇”演习中空战科目演练。\n\n" +
                "【“对抗虎”联合空战演习】“对抗虎”联合空战演习是美国、泰国和新加坡空军联合" +
                "举行的年度空战演习。2019 年是第 25 届，于 3 月 11 日至 22 日在泰国举行，参演兵力包括" +
                "驻日美空军三泽基地第 14 战斗机中队 12 架 F-16C/D 战斗机，泰国、新加坡空军相关单位共" +
                "计 1150 人。演习主要开展空战演练、防空火力压制等科目演练，演习期间三国空军共执行" +
                "了 776 个架次的飞行任务，其中美空军第 14 战斗机中队执行了 136 个架次并且还为参演部" +
                "队提供了模拟假想敌防空压制。此外美军还为泰国空军提供了联合末端攻击引导员项目培" +
                "训，其中，美国华盛顿州空中国民警卫队 116 空中支援作战中队教授泰国空军人员如何引导" +
                "新加坡空军 2 架 F-15 战斗机实施空对地打击行动。\n\n" +
                "【“守卫海洋 2019”联合演习】“守卫海洋 2019”联合演习（Exercise Guardian Sea" +
                "2019）是美泰两国海军组织的大型联合反潜演习，2019 年是该演习第 8 次举行。演习于 4" +
                "月中旬在安达曼海举行，参演兵力包括美海军洛杉矶级核动力攻击潜艇路易斯维拉号（USS" +
                "Louisville，SSN-724）、1 艘后勤补给油船；泰国海军 2 艘护卫舰、1 艘巡逻船和 1 架海鹰" +
                "直升机。此次演习分为岸上专家交流会和海上潜艇追踪两个阶段进行，演习中泰国海军护卫" +
                "舰 首次装备使用拖拽式阵列声纳执行反潜任务。\n\n" +
                "【“对抗西 2019”野战训练演习】“对抗西 2019”野战训练演习（Cope West 2019" +
                "Field Training Exercise）是美印（尼）两国空军举行的年度联合空战演习。该演习于 6" +
                "月 17 日至 28 日在印尼北苏拉威西省万鸦老机场举行。美空军第 14 战斗机中队 6 架 F-" +
                "16C/D 战斗机与印尼空军 6 架 F-16 战斗机参加。演习科目包括飞机维护技巧、近地支援作" +
                "战训练、空对空作战训练以及主题专家交流会等。\n\n" +
                "【“卡拉特”联合演习】“卡拉特”联合演习（Cooperation Afloat Readiness and" +
                "Training，CARAT）又称海上战备与训练合作，是美国与南亚和东盟部分国家开展的大型年" +
                "度海上联合演习。2019 年演习从 4 月 22 日美国、斯里兰卡“卡拉特”联合演习开始一直持" +
                "续至 11 月初，目前已经举行了美斯（4 月 22 日）、美泰（5 月 29 日至 6 月 8 日）、美印" +
                "（尼）（8 月 1 日至 7 日）、美文（莱）（10 月 22 日）、美孟（11 月 4 日至 8 日）四场联" +
                "合演习。在美斯“卡拉特”联合演习中美海军导弹驱逐舰斯普鲁恩斯号（USS Spruance，" +
                "DDG-111）、P-8A 反潜巡逻机参加；在美泰“卡拉特”联合演习中美海军导弹巡洋舰安提坦" +
                "号（USS Antietam ，CG-54）、水雷对抗舰爱国者号（USS Patriot，MCM-7）、先锋号" +
                "（USS Pioneer，MCM-9）、打捞船打捞者号、远征快速运输船米利诺克特号，美海军陆战队" +
                "驻澳大利亚达尔文轮换部队、第七舰队乐队、第 5 爆炸物处置机动部队和海军第 6 环境预防" +
                "和医疗部队参加；在美印（尼）“卡拉特”联合演习中美海军 73 特混部队和第 7 驱逐舰中" +
                "队的参谋人员、濒海战斗舰蒙哥马利号、远征快速运输船瀑布河号、海警船斯特拉顿号、运" +
                "输船卡洛琳·丘伊斯特号（MV Carolyn Chouest）、海军第 6 环境河医疗预防部队、第 7 舰" +
                "队乐队和 1 架 P-8A 反潜巡逻机参加；在美文（莱）“卡拉特”联合演习中美海军两栖船坞" +
                "登陆舰哈珀斯·费里号（USS Harper’s Ferry，LSD-49）、美海军 P-8A 反潜巡逻机参加；" +
                "美孟“卡拉特”联合演习中美海军第 72、73 特混部队、第 7 驱逐舰中队、第 1 机动潜水打" +
                "捞部队、45 巡逻中队的 1 架 P-8A 反潜巡逻机参加。美海军在与各国举行的“卡拉特”联合" +
                "演习中，演习科目大同小异但是又略有侧重，基本上演习科目都会涵盖水面战机动战术、登" +
                "临搜捕演练、机动潜水和打捞训练、爆炸物排除、扫雷和海上巡逻作战等方面。";

        String dir = CommonConstant.UPLOAD_DIR;
        File dirFile = new File(dir);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }

        String saveFileName = TimeFormatUtil.getCurrentTimeString() + "_" + fileName + ".txt";
        String filePath = dir + saveFileName;

        File textFile = new File(filePath);
        textFile.createNewFile();
        BufferedWriter out = new BufferedWriter(new FileWriter(textFile));
        out.write(content);
        out.flush();
        out.close();

        int userId = UserLoginUtils.getUser().getUserId();
        com.swt.gap.model.entity.File file  = new com.swt.gap.model.entity.File();
        file.setCreatedBy(userId);
        file.setCreatedTime(new Date());
        file.setOriginalFileName(fileName);
        file.setFileType(2);
        file.setFileClassId(0);
        file.setIsDeleted(false);
        //数据来源
        file.setFileFromType(1);
        file.setSavedFileName(saveFileName);
//        file.setSavePath(CommonConstant.RELATIVE_DIR + saveFileName);
        fileDao.insertSelective(file);

        int fileId = file.getFileId();

        return taskFileService.addTaskFiles(taskId, Collections.singletonList(fileId));

    }

    @Override
    public Boolean test(String fileName, Integer taskId, Integer fileId) {
        TextFileModelVO model = new TextFileModelVO();
        List<String> header1 = Arrays.asList("名称,开始时间,结束时间,地点,国家,军队,装备".split(","));
        List<List<String>> rows = new ArrayList<>();
        List<String> row = Arrays.asList("美菲“肩并肩”联合演习@2019-04-01 00:00:00@2019-04-12 00:00:00@菲律宾马尼拉@美国,菲律宾@美国海军,美海军陆战队,菲律宾海军@F-35B,黄蜂号两栖攻击舰".split("@"));
        rows.add(row);
        row = Arrays.asList("美菲“盾牌”联合演习@2019-03-04 00:00:00@2019-03-24 00:00:00@菲律宾帕拉延市@美国,菲律宾@美陆军第7步兵师,菲律宾陆军第7步兵师@,".split("@"));
        rows.add(row);
        row = Arrays.asList("“海上勇士合作 3”联合演习@2019-10-09 00:00:00@@菲律宾马尼拉@美国,菲律宾,日本@美国海军,美海军陆战队,日本自卫队@杰曼敦号两栖船坞登陆舰".split("@"));
        rows.add(row);
        row = Arrays.asList("“萨马萨马”海上训练活动@2019-10-14 00:00:00@@菲律宾普林塞萨港@美国,菲律宾,日本@日本海上自卫队,美国海岸警卫队@濒海战斗舰蒙哥马利号,杰曼敦号两栖船坞登陆舰,P-8A反潜巡逻机,海警船斯特拉顿号".split("@"));
        rows.add(row);
        row = Arrays.asList("“哈努曼守卫者19”年度联合演习@2019-01-28 00:00:00@@泰国@美国,泰国@美太平洋陆军司令部,泰国陆军@濒海战斗舰蒙哥马利号,杰曼敦号两栖船坞登陆舰".split("@"));
        rows.add(row);
        row = Arrays.asList("“金色眼镜蛇”联合演习@2019-02-12 00:00:00@@泰国梭桃邑@美国,泰国,印尼,马来西亚,新加坡@美国海军,美海军陆战队,美国空军@格林湾号两栖船坞运输舰,F-16C".split("@"));
        rows.add(row);
        row = Arrays.asList("“对抗虎”联合空战演习@2019-03-11 00:00:00@@泰国@美国,泰国,新加坡@美国空军第14战斗机中队,空中国民警卫队@F-16C,F-15".split("@"));
        rows.add(row);
        row = Arrays.asList("“守卫海洋2019”联合演习@2019-04-01 00:00:00@@泰国@美国,泰国@美国海军,泰国海军@洛杉矶级核动力攻击潜艇路易斯维拉号".split("@"));
        rows.add(row);
        row = Arrays.asList("“对抗西 2019”野战训练演习@2019-06-17 00:00:00@@印度尼西亚北苏拉威西省@美国,印尼@美国空军第14战斗机中队,印尼空军@F-16C/D,F-16".split("@"));
        rows.add(row);
        row = Arrays.asList("“卡拉特”联合演习@2019-04-22 00:00:00@@印尼@美国,斯里兰卡,菲律宾,泰国,印尼,文莱,孟加拉国@美国海军,美国海岸警卫队@导弹驱逐舰斯普鲁恩斯号,P-8A反潜巡逻机,导弹巡洋舰安提坦号,水雷对抗舰爱国者号,濒海战斗舰蒙哥马利号,两栖船坞登陆舰哈珀斯·费里号,海警船斯特拉顿号".split("@"));
        rows.add(row);
        row = Arrays.asList("“海猫”演习@2019-08-19 00:00:00@@新加坡@美国,孟加拉国,文莱,柬埔寨,印尼,马来西亚,菲律宾,新加坡,斯里兰卡,泰国,越南@美国海军,美国海岸警卫队@P-8A反潜巡逻机".split("@"));
        rows.add(row);
        row = Arrays.asList("马来西亚海上训练活动 2019@2019-08-14 00:00:00@@马来西亚@美国,马来西亚@美国海军,美国海岸警卫队@濒海战斗舰蒙哥马利号,海警船斯特拉顿号".split("@"));
        rows.add(row);
        row = Arrays.asList("“虎击”19 联合演习@2019-09-30 00:00:00@@马来西亚@美国,马来西亚@美海军陆战队@AV-8B攻击机,MV-22B偏转翼运输机,海警船斯特拉顿号".split("@"));
        rows.add(row);
        row = Arrays.asList("东盟-美国海上演习@2019-09-02 00:00:00@@泰国湾@美国,菲律宾,新加坡@美国海军@濒海战斗舰蒙哥马利号,导弹驱逐舰迈耶号,P-8A反潜巡逻机".split("@"));
        rows.add(row);
        row = Arrays.asList("“太平洋格里芬”演习@2019-09-27 00:00:00@@关岛@美国,新加坡@美国海军,新加坡海军@濒海战斗舰吉福兹号,导弹驱逐舰莫姆森号,核动力攻击潜艇基韦斯特号,P-8A反潜巡逻机,B-52H轰炸机".split("@"));
        rows.add(row);
        row = Arrays.asList("“对抗北方”演习@2019-02-18 00:00:00@@关岛@美国,日本,澳大利亚@美国海军,美海军陆战队,美国空军,日本自卫队,澳大利亚空军@濒海战斗舰吉福兹号,导弹驱逐舰莫姆森号,核动力攻击潜艇基韦斯特号,P-8A反潜巡逻机,B-52H轰炸机".split("@"));
        rows.add(row);
        row = Arrays.asList("战术演练@2019-03-19 00:00:00@@菲律宾@美国,菲律宾@美国海军,菲律宾海军@美海军蓝岭号两栖指挥舰".split("@"));
        rows.add(row);
        model.setTextContent(new FormDataVO(header1, rows));

//        List<EventGraphModel> listEventTemplate = modelService.getModelById(31).getEventModels();

        List<GraphTemplate> listTemplate = new ArrayList<>();


        Map<String, GraphNeo4jVO.Node> mapNodes = new HashMap<>();
        Map<String, GraphNeo4jVO.Link> mapLinks = new HashMap<>();


        List<FileFilterConfig.FieldFilterConfig> fieldFilterConfigList = new ArrayList<>();
        List<Map<String, String>> rowDataList = new ArrayList<>();

        List<String> header = model.getTextContent().getHeader();

        for (int i = 0; i < model.getTextContent().getRows().size(); i++) {
            Map<String, String> rowData = new HashMap<>();
            for (int j = 0; j < header.size(); j++) {
                rowData.put(header.get(j), model.getTextContent().getRows().get(i).get(j));
            }
            rowDataList.add(rowData);
        }

//        processFileContent(taskId, fileName, listTemplate, listEventTemplate, mapNodes, mapLinks,
//                    rowDataList, fieldFilterConfigList, 2);
//
//
//        List<GraphNeo4jVO.Node> listNodes = new ArrayList<>();
//        mapNodes.forEach((k, v) -> listNodes.add(v));
//
//        List<GraphNeo4jVO.Link> listLinks = new ArrayList<>();
//        mapLinks.forEach((k, v) -> listLinks.add(v));
        List<GraphModel> graphModels = model2Service.getModelById(4).getGraphModels();
        Graph graph = graphDataTransferService.processFormData(taskId, fileName, graphModels,
                rowDataList, 2, fieldFilterConfigList, false);
        graphDataTransferService.importData(graph, taskId,fileId, "", graphModels);

        DocImportVO record = new DocImportVO();
        GraphNeo4jVO.Node docNode = new GraphNeo4jVO.Node();
        docNode.setLabels(Arrays.asList("文档","多媒体"));

        GraphNeo4jVO.Node otherNode = new GraphNeo4jVO.Node();
        otherNode.setLabels(Arrays.asList("事件","演习事件"));
        Map<String, Object> properties = new HashMap<>();
        properties.put("name", "美菲“肩并肩”联合演习");
        properties.put("名称", "美菲“肩并肩”联合演习");
        otherNode.setProperties(properties);
//        for(GraphNeo4jVO.Node node : listNodes) {
//            if (null!=node.getProperties() && node.getProperties().containsKey("name") && "美菲“肩并肩”联合演习".equals(node.getProperties().get("name").toString())) {
//                otherNode = node;
//                break;
//            }
//        }

        GraphNeo4jVO.Link link = new GraphNeo4jVO.Link();
        link.setType("相关");
        link.setDirection(2);

        record.setOtherNode(otherNode);
        record.setDocNode(docNode);
        record.setLink(link);
        record.setTaskId(taskId);
        record.setSavedFileName("肩并肩.jpg");
        importDocGraph(record);
        taskFileMapper.updateStatus(fileId, taskId, 1);

        return true;
    }

    @Override
    public Boolean autoImportFileGraph(List<Integer> fileIds, Integer taskId) {
        List<FileFilterConfig.FieldFilterConfig> fieldFilterConfigList = new ArrayList<>();
        for (Integer fileId : fileIds) {
            List<Map<String, String>> rowDataList = new ArrayList<>();
            com.swt.gap.model.entity.File file = fileDao.selectByPrimaryKey(fileId);
            EventExtractVO eventExtract = JSON.parseObject(file.getTextElement().toJSONString(), EventExtractVO.class);
            List<ElementValueDTO> eventElements = eventExtract.getEventElements();
            List<String> headers = new ArrayList<>();
            Map<String, String> mapRow = new HashMap<>();
            eventElements.forEach(eventElement -> {
                headers.add(eventElement.getElement());
                eventElement.getElementTexts().forEach(elementText -> {
                    mapRow.merge(eventElement.getElement(), elementText.getText(), (oldValue, newValue) -> oldValue + "," + newValue);
                });
            });
            rowDataList.add(mapRow);
            // 根据表头匹配模型
            List<GraphModel> graphModels = model2Service.getRecommendModel(headers).getGraphModels();
            Graph graph = graphDataTransferService.processFormData(taskId, file.getSavedFileName(), graphModels,
                    rowDataList, 2, fieldFilterConfigList, false);
            graphDataTransferService.importData(graph, taskId, fileId, "", graphModels);
        }
        return true;
    }

    @Override
    public Boolean isWaiting(PreviewGraphDataVO record) {
        boolean result = false;
        String savedFileName = record.getSavedFileName();
        if (record.getFileType().equals(FileTypeEnum.WORD07.getDataTypeCode())) {
            result = record.getTextContent().getRows().size() > BIG_ROW_COUNT;

        } else if (record.getFileType().equals(FileTypeEnum.CSV.getDataTypeCode())){
            String filePath = CommonConstant.UPLOAD_DIR + savedFileName;
            if (filePath.endsWith(FileTypeEnum.CSV.getSuffix())) {
                cn.hutool.core.text.csv.CsvReader reader = CsvUtil.getReader(csvReadConfig);
                CsvData data = reader.read(FileUtil.file(filePath), StandardCharsets.UTF_8);
                result = data.getRows().size() > BIG_ROW_COUNT;
            } else if (filePath.endsWith(FileTypeEnum.EXCEL03.getSuffix()) || filePath.endsWith(FileTypeEnum.EXCEL07.getSuffix())) {
                ExcelData data = com.swt.gap.util.excel.ExcelUtil.getReader().read(filePath);
                result = data.getFieldsMap().size() > BIG_ROW_COUNT;
            }
        }
        return result;
    }
}
